"""
@File    : query_name_to_task.py
@Author  : timo.tan
@Time    : 2025/07/31 12:18 
"""

import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
import time
from datetime import datetime, timedelta


# 认证Token
AUTH_TOKEN = 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEzMjk4LCJpc3MiOiJjZ2Jvc3MiLCJleHAiOjE3NTYyNjIxMTIsIm5iZiI6MTc1MzY3MDExMiwiaWF0IjoxNzUzNjcwMTEyfQ.ifaIeAEp6SWTZTbQ2iZxPJrVVcn-MuI9C5E9zbGmLsk'

def get_auth_token():
    """获取认证Token"""
    return AUTH_TOKEN

def fetch_single_page(url, headers, page_no, page_size, api_name):
    """
    获取单页数据（线程安全）
    Args:
        url: API地址
        headers: 请求头
        page_no: 页码
        page_size: 页大小
        api_name: API名称（用于错误提示）
    Returns:
        tuple: (page_no, tasks_list, success, error_msg)
    """
    try:
        data = {"page":{"no":page_no,"size":page_size},"pstatus":-1}
        response = requests.post(url=url, headers=headers, json=data, timeout=30)
        
        if not response.ok:
            return page_no, [], False, f"HTTP {response.status_code}"
            
        result = response.json()
        ret = result.get('ret', {})
        if ret.get('code') != 0:
            return page_no, [], False, ret.get('msg', '未知错误')
        
        # 获取当前页数据
        body = result.get('body', {})
        current_tasks = body.get('list', [])
        
        return page_no, current_tasks, True, None
        
    except requests.RequestException as e:
        return page_no, [], False, f"网络异常: {str(e)}"
    except Exception as e:
        return page_no, [], False, f"未知错误: {str(e)}"

def get_week_ago_timestamp():
    """获取一周前的时间戳"""
    week_ago = datetime.now() - timedelta(days=7)
    return int(week_ago.timestamp())

def format_timestamp(timestamp_str):
    """将时间戳字符串转换为可读格式"""
    try:
        if not timestamp_str or timestamp_str == "0":
            return "未设置"
        timestamp = int(timestamp_str)
        dt = datetime.fromtimestamp(timestamp)
        return dt.strftime("%Y-%m-%d %H:%M:%S")
    except (ValueError, OSError):
        return f"无效时间({timestamp_str})"

def is_within_last_week(timestamp_str):
    """检查时间戳是否在最近一周内"""
    try:
        if not timestamp_str or timestamp_str == "0":
            return False
        timestamp = int(timestamp_str)
        week_ago_timestamp = get_week_ago_timestamp()
        return timestamp >= week_ago_timestamp
    except (ValueError, OSError):
        return False

def fetch_api_data_concurrent(url, api_name, page_size=100, get_all=True, max_workers=8):
    """
    多线程并发获取API数据
    Args:
        url: API地址
        api_name: API名称
        page_size: 每页大小
        get_all: 是否获取所有数据
        max_workers: 最大线程数
    Returns:
        dict: API返回的完整数据，包含所有分页结果
    """
    headers = {'Authorization': get_auth_token()}
    
    # 第一步：获取第一页，了解总数据量
    print(f"📊 {api_name}: 正在探测数据总量...")
    page_no, first_page_tasks, success, error_msg = fetch_single_page(url, headers, 1, page_size, api_name)
    
    if not success:
        print(f"❌ {api_name} 第一页获取失败: {error_msg}")
        return None
    
    if not get_all:
        # 如果只需要第一页，直接返回
        return {
            'success': True,
            'ret': {'code': 0},
            'body': {
                'list': first_page_tasks,
                'total': len(first_page_tasks)
            }
        }
    
    # 通过第一页数据估算总页数（这里我们需要重新请求获取准确的total）
    data = {"page":{"no":1,"size":page_size},"pstatus":-1}
    response = requests.post(url=url, headers=headers, json=data, timeout=30)
    result = response.json()
    total_tasks = result.get('body', {}).get('total', 0)
    
    if total_tasks == 0:
        return {
            'success': True,
            'ret': {'code': 0},
            'body': {
                'list': [],
                'total': 0
            }
        }
    
    total_pages = (total_tasks + page_size - 1) // page_size
    print(f"📊 {api_name}: 总任务数 {total_tasks:,}，共 {total_pages} 页，使用 {min(max_workers, total_pages)} 个线程并发获取")
    
    # 第二步：多线程并发获取所有页面
    all_tasks = []
    failed_pages = []
    
    # 优化线程数：不要超过总页数
    actual_workers = min(max_workers, total_pages)
    
    with ThreadPoolExecutor(max_workers=actual_workers) as executor:
        # 提交所有页面的获取任务
        future_to_page = {
            executor.submit(fetch_single_page, url, headers, page_no, page_size, api_name): page_no
            for page_no in range(1, total_pages + 1)
        }
        
        # 收集结果
        completed_pages = 0
        for future in as_completed(future_to_page):
            page_no, tasks, success, error_msg = future.result()
            completed_pages += 1
            
            if success:
                all_tasks.extend(tasks)
                if completed_pages % 10 == 0 or completed_pages == total_pages:
                    print(f"📈 {api_name}: 已完成 {completed_pages}/{total_pages} 页，获取任务 {len(all_tasks):,} 个")
            else:
                failed_pages.append((page_no, error_msg))
                print(f"⚠️ {api_name}: 第{page_no}页获取失败 - {error_msg}")
    
    if failed_pages:
        print(f"⚠️ {api_name}: {len(failed_pages)} 页获取失败，成功获取 {len(all_tasks):,}/{total_tasks:,} 个任务")
    else:
        print(f"✅ {api_name}: 全部 {total_pages} 页获取成功，共 {len(all_tasks):,} 个任务")
    
    return {
        'success': True,
        'ret': {'code': 0},
        'body': {
            'list': all_tasks,
            'total': total_tasks
        }
    }

# 控制台任务
def get_cgboss_data(page_size=100, get_all=True, max_workers=8):
    """
    获取cgboss任务数据（多线程并发版本）
    Args:
        page_size: 每页大小，默认100
        get_all: 是否获取所有数据，默认True
        max_workers: 最大线程数，默认8
    Returns:
        dict: API返回的完整数据，包含所有分页结果
    """
    url = 'https://cgboss.yuntiancloud.com/api/cgboss/v1/task/plist'
    return fetch_api_data_concurrent(url, "cgboss", page_size, get_all, max_workers)
# 服务组任务
def get_cgbundle_data(page_size=100, get_all=True, max_workers=8):
    """
    获取cgbundle任务数据（多线程并发版本）
    Args:
        page_size: 每页大小，默认100
        get_all: 是否获取所有数据，默认True
        max_workers: 最大线程数，默认8
    Returns:
        dict: API返回的完整数据，包含所有分页结果
    """
    url = 'https://cgboss.yuntiancloud.com/api/cgbundle/v1/task/plist'
    return fetch_api_data_concurrent(url, "cgbundle", page_size, get_all, max_workers)

# 实例任务
def get_cginstance_data(page_size=100, get_all=True, max_workers=8):
    """
    获取cginstance任务数据（多线程并发版本）
    Args:
        page_size: 每页大小，默认100
        get_all: 是否获取所有数据，默认True
        max_workers: 最大线程数，默认8
    Returns:
        dict: API返回的完整数据，包含所有分页结果
    """
    url = 'https://cgboss.yuntiancloud.com/api/cginstance/v1/task/plist'
    return fetch_api_data_concurrent(url, "cginstance", page_size, get_all, max_workers)

def check_single_api_count(api_name, api_func):
    """
    检查单个API的任务数量（线程安全）
    """
    try:
        result = api_func(page_size=10, get_all=False, max_workers=1)  # 数量检查只需要1个线程
        if result:
            total = result.get('body', {}).get('total', 0)
            return api_name, total, True
        else:
            return api_name, 0, False
    except Exception as e:
        print(f"❌ {api_name} 查询异常: {str(e)}")
        return api_name, 0, False

def check_task_counts():
    """
    并发检查不同任务类型的数量（只获取第一页获取总数，提高效率）
    """
    # 定义API映射
    api_configs = [
        ('cgboss', get_cgboss_data),
        ('cgbundle', get_cgbundle_data),
        ('cginstance', get_cginstance_data)
    ]
    
    # API名称到图标的映射
    api_icons = {
        'cgboss': '🎮 cgboss (控制台任务)',
        'cgbundle': '📦 cgbundle (服务组任务)',
        'cginstance': '⚙️ cginstance (实例任务)'
    }
    
    totals = {}
    
    # 使用线程池并发查询数量
    with ThreadPoolExecutor(max_workers=8) as executor:
        # 提交所有查询任务
        future_to_api = {
            executor.submit(check_single_api_count, api_name, api_func): api_name
            for api_name, api_func in api_configs
        }
        
        # 收集结果
        for future in as_completed(future_to_api):
            api_name, total, success = future.result()
            
            if success:
                totals[api_name] = total
                print(f"{api_icons[api_name]}: {total:,} 个")
            else:
                print(f"❌ {api_name} 任务查询失败")
    
    return totals

def filter_single_api_tasks(api_name, api_func, user_cn_name="谭华宝", filter_recent_week=True, max_workers=8):
    """
    单个API的任务筛选（线程安全）
    Args:
        api_name: API名称
        api_func: API函数
        user_cn_name: 用户中文名
        filter_recent_week: 是否只显示最近一周的任务
        max_workers: 最大线程数
    Returns:
        tuple: (api_name, filtered_tasks, total_tasks, user_total_tasks)
    """
    print(f"🔍 正在查询 {api_name} 任务...")
    start_time = time.time()
    
    try:
        api_data = api_func(max_workers=max_workers)
        if api_data and api_data.get('success'):
            tasks = api_data.get('body', {}).get('list', [])
            total_tasks = api_data.get('body', {}).get('total', 0)
            
            # 先筛选目标用户的所有任务
            user_tasks = [
                task for task in tasks
                if task.get('userCNName') == user_cn_name
            ]
            
            # 再根据时间过滤（如果需要）
            if filter_recent_week:
                filtered_tasks = []
                for task in user_tasks:
                    start_time_str = task.get('startTime', '0')
                    if is_within_last_week(start_time_str):
                        filtered_tasks.append({
                            'pid': task.get('pid'),
                            'content': task.get('content'),
                            'startTime': start_time_str,
                            'formatted_time': format_timestamp(start_time_str)
                        })
                
                elapsed = time.time() - start_time
                print(f"✅ {api_name} 查询完成: {user_cn_name}总任务{len(user_tasks)}个，最近一周{len(filtered_tasks)}个 (总任务数: {total_tasks:,}，耗时: {elapsed:.2f}s)")
            else:
                filtered_tasks = [
                    {
                        'pid': task.get('pid'),
                        'content': task.get('content'),
                        'startTime': task.get('startTime', '0'),
                        'formatted_time': format_timestamp(task.get('startTime', '0'))
                    }
                    for task in user_tasks
                ]
                
                elapsed = time.time() - start_time
                print(f"✅ {api_name} 查询完成: 找到 {len(filtered_tasks)} 个{user_cn_name}的任务 (总任务数: {total_tasks:,}，耗时: {elapsed:.2f}s)")
            
            return api_name, filtered_tasks, total_tasks, len(user_tasks)
        else:
            print(f"❌ {api_name} 查询失败")
            return api_name, [], 0, 0
            
    except Exception as e:
        print(f"❌ {api_name} 查询异常: {str(e)}")
        return api_name, [], 0, 0

def filter_tasks_by_user_concurrent(user_cn_name="谭华宝", max_workers=3, filter_recent_week=True):
    """
    并发查询所有任务并根据userCNName筛选，返回pid、content和startTime
    Args:
        user_cn_name: 用户中文名，默认为"谭华宝"
        max_workers: 最大并发线程数，默认3
        filter_recent_week: 是否只显示最近一周的任务，默认True
    Returns:
        dict: 包含三个任务类型筛选结果的字典
    """
    result = {
        'cgboss_tasks': [],
        'cgbundle_tasks': [],
        'cginstance_tasks': [],
        'total_count': 0,
        'user_total_count': 0,
        'api_totals': {},
        'user_totals': {},
        'filter_info': {
            'filter_recent_week': filter_recent_week,
            'week_ago_date': datetime.now() - timedelta(days=7)
        }
    }
    
    # 定义API映射
    api_configs = [
        ('cgboss', get_cgboss_data),
        ('cgbundle', get_cgbundle_data), 
        ('cginstance', get_cginstance_data)
    ]
    
    filter_msg = "最近一周" if filter_recent_week else "全部"
    print(f"🚀 开始并发查询 {user_cn_name} 的{filter_msg}任务...")
    overall_start = time.time()
    
    # 使用线程池并发执行
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        # 提交所有任务
        future_to_api = {
            executor.submit(filter_single_api_tasks, api_name, api_func, user_cn_name, filter_recent_week, max_workers): api_name
            for api_name, api_func in api_configs
        }
        
        # 收集结果
        for future in as_completed(future_to_api):
            api_name, filtered_tasks, total_tasks, user_total_tasks = future.result()
            
            # 根据API名称存储结果
            if api_name == 'cgboss':
                result['cgboss_tasks'] = filtered_tasks
            elif api_name == 'cgbundle':
                result['cgbundle_tasks'] = filtered_tasks
            elif api_name == 'cginstance':
                result['cginstance_tasks'] = filtered_tasks
            
            result['api_totals'][api_name] = total_tasks
            result['user_totals'][api_name] = user_total_tasks
    
    # 计算总数
    result['total_count'] = (len(result['cgboss_tasks']) + 
                           len(result['cgbundle_tasks']) + 
                           len(result['cginstance_tasks']))
    
    result['user_total_count'] = sum(result['user_totals'].values())
    
    overall_elapsed = time.time() - overall_start
    if filter_recent_week:
        print(f"🎉 并发查询完成！总耗时: {overall_elapsed:.2f}s")
        print(f"   {user_cn_name}全部任务: {result['user_total_count']}个")
        print(f"   最近一周任务: {result['total_count']}个")
    else:
        print(f"🎉 并发查询完成！总耗时: {overall_elapsed:.2f}s，找到 {result['total_count']} 个{user_cn_name}的任务")
    
    return result

def filter_tasks_by_user(user_cn_name="谭华宝"):
    """
    兼容性函数，使用并发版本
    """
    return filter_tasks_by_user_concurrent(user_cn_name)

def get_all_tasks_by_user(user_cn_name="谭华宝"):
    """
    获取指定用户的所有任务（简化版本，只返回pid和content列表）
    Args:
        user_cn_name: 用户中文名
    Returns:
        list: 包含所有匹配任务的pid和content的列表
    """
    all_tasks = []
    
    # 获取详细筛选结果
    filtered_result = filter_tasks_by_user(user_cn_name)
    
    # 合并所有任务
    all_tasks.extend(filtered_result['cgboss_tasks'])
    all_tasks.extend(filtered_result['cgbundle_tasks'])
    all_tasks.extend(filtered_result['cginstance_tasks'])
    
    return all_tasks

def parse_task_log_text(task_log_text):
    """
    解析任务日志文本，按照指定顺序排序：cgboss -> cgbundle -> cginstance
    Args:
        task_log_text: 任务日志的文本字符串
    Returns:
        dict: 按类型分组的任务列表
    """
    lines = task_log_text.strip().split('\n')
    tasks = {
        'cgboss': [],
        'cgbundle': [],
        'cginstance': []
    }
    
    for line in lines:
        line = line.strip()
        if not line:
            continue
            
        # 解析每行数据
        parts = line.split(None, 5)  # 最多分割5次，保证内容完整
        if len(parts) >= 5:
            line_num = parts[0]
            emoji_type = parts[1] + " " + parts[2]  # "⚙️ cginstance" 或 "🎮 cgboss"
            task_id = parts[3]
            date = parts[4]
            time_part = parts[5] if len(parts) > 5 else ""
            
            # 提取任务内容（从时间后开始）
            remaining_text = " ".join(parts[5:]) if len(parts) > 5 else ""
            content = remaining_text.split("  ", 1)[-1] if "  " in remaining_text else remaining_text
            
            # 确定任务类型
            task_type = None
            if "cgboss" in emoji_type:
                task_type = "cgboss"
            elif "cgbundle" in emoji_type:
                task_type = "cgbundle"  
            elif "cginstance" in emoji_type:
                task_type = "cginstance"
            
            if task_type:
                tasks[task_type].append({
                    'line_num': line_num,
                    'emoji_type': emoji_type,
                    'task_id': task_id,
                    'datetime': f"{date} {time_part.split()[0] if time_part else ''}".strip(),
                    'content': content.strip()
                })
    
    return tasks

def display_sorted_tasks(tasks):
    """
    按照指定顺序显示任务：cgboss -> cgbundle -> cginstance
    Args:
        tasks: parse_task_log_text函数返回的任务字典
    """
    print("📋 任务列表（按类型排序：cgboss -> cgbundle -> cginstance）")
    print("=" * 120)
    print(f"{'序号':<4} {'类型':<15} {'任务ID':<8} {'创建时间':<20} {'任务内容':<60}")
    print("-" * 120)
    
    counter = 1
    
    # 按照指定顺序显示：cgboss -> cgbundle -> cginstance
    for task_type in ['cgboss', 'cgbundle', 'cginstance']:
        type_tasks = tasks[task_type]
        if type_tasks:
            print(f"\n{get_task_type_icon(task_type)} {task_type.upper()} 任务 ({len(type_tasks)}个):")
            for task in type_tasks:
                content = task['content'][:55] + "..." if len(task['content']) > 55 else task['content']
                print(f"{counter:<4} {task['emoji_type']:<15} {task['task_id']:<8} {task['datetime']:<20} {content:<60}")
                counter += 1
    
    print("-" * 120)
    total_tasks = sum(len(tasks[t]) for t in tasks)
    print(f"任务统计：cgboss({len(tasks['cgboss'])}个) + cgbundle({len(tasks['cgbundle'])}个) + cginstance({len(tasks['cginstance'])}个) = 总计{total_tasks}个")

def get_task_type_icon(task_type):
    """获取任务类型对应的图标"""
    icons = {
        'cgboss': '🎮',
        'cgbundle': '📦', 
        'cginstance': '⚙️'
    }
    return icons.get(task_type, '📋')

def display_task_details(result, user_cn_name="谭华宝"):
    """显示任务详细信息"""
    all_tasks = []
    
    # 收集所有任务 - 按照指定顺序：cgboss -> cgbundle -> cginstance
    for task_type, tasks in [
        ('🎮 cgboss', result['cgboss_tasks']),
        ('📦 cgbundle', result['cgbundle_tasks']),
        ('⚙️ cginstance', result['cginstance_tasks'])
    ]:
        for task in tasks:
            all_tasks.append({
                'type': task_type,
                'pid': task['pid'],
                'content': task['content'],
                'startTime': task['startTime'],
                'formatted_time': task['formatted_time']
            })
    
    if all_tasks:
        print(f"\n📋 {user_cn_name}最近一周的任务详情（cgboss -> cgbundle -> cginstance）:")
        print("=" * 120)
        print(f"{'序号':<4} {'类型':<12} {'PID':<8} {'创建时间':<20} {'任务内容':<60}")
        print("-" * 120)
        
        # 按任务类型优先级排序，同类型内按时间排序（最新的在前）
        task_priority = {'🎮 cgboss': 1, '📦 cgbundle': 2, '⚙️ cginstance': 3}
        all_tasks.sort(key=lambda x: (
            task_priority.get(x['type'], 4),  # 先按类型优先级排序
            -int(x['startTime']) if x['startTime'].isdigit() else 0  # 同类型内按时间倒序
        ))
        
        for i, task in enumerate(all_tasks, 1):
            content = task['content'][:55] + "..." if len(task['content']) > 55 else task['content']
            print(f"{i:<4} {task['type']:<12} {task['pid']:<8} {task['formatted_time']:<20} {content:<60}")
        
        print("-" * 120)
        print(f"共找到 {len(all_tasks)} 个最近一周的任务")
    else:
        print(f"\n📋 {user_cn_name}最近一周没有任务")

if __name__ == '__main__':
    print("🚀 开始任务统计与查询（多线程并发版本）")
    print("=" * 80)
    
    # 示例：解析并排序任务日志文本
    print("📋 示例：解析任务日志文本并按类型排序")
    sample_task_log = """1    ⚙️ cginstance 30454    2025-07-30 18:34:53  任务来源：CGBoss，实例数量：1
2    ⚙️ cginstance 30428    2025-07-30 17:03:41  任务来源：CGBoss，实例数量：6
3    🎮 cgboss     22372    2025-07-30 16:59:30  逆水寒手游微端游戏集(V1628.3)-扩容实例数:1
4    🎮 cgboss     22366    2025-07-30 16:48:50  逆水寒手游微端游戏集(V1628.3)-扩容实例数:2
5    🎮 cgboss     22353    2025-07-30 15:49:35  逆水寒手游微端游戏集(V1628.3)-扩容实例数:12
6    ⚙️ cginstance 30388    2025-07-30 15:09:02  任务来源：CGBoss，实例数量：6
7    ⚙️ cginstance 30383    2025-07-30 14:46:27  任务来源：CGBoss，实例数量：18
8    ⚙️ cginstance 30376    2025-07-30 14:30:38  任务来源：CGBoss，实例数量：10"""
    
    # 解析任务日志
    parsed_tasks = parse_task_log_text(sample_task_log)
    
    # 按照指定顺序显示：cgboss -> cgbundle -> cginstance
    display_sorted_tasks(parsed_tasks)
    
    print("\n" + "=" * 80)
    
    # 第一步：并发获取各任务类型总数量
    print("📊 第一步：各任务类型总数量统计（并发查询）")
    start_time = time.time()
    task_counts = check_task_counts()
    count_elapsed = time.time() - start_time
    
    if task_counts:
        total_all = sum(task_counts.values())
        print(f"📋 所有任务总计: {total_all:,} 个")
        print(f"⏱️ 数量统计耗时: {count_elapsed:.2f}s")
    
    print("\n" + "=" * 80)
    
    # 第二步：并发查询谭华宝最近一周的任务
    week_ago_str = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")
    print(f"🔍 第二步：查询谭华宝最近一周的任务（{week_ago_str}至今）")
    filter_start = time.time()
    result = filter_tasks_by_user_concurrent("谭华宝", max_workers=8, filter_recent_week=True)
    filter_elapsed = time.time() - filter_start
    
    print("\n📝 统计结果:")
    print(f"🎮 cgboss任务: {len(result['cgboss_tasks'])}个")
    print(f"📦 cgbundle任务: {len(result['cgbundle_tasks'])}个") 
    print(f"⚙️ cginstance任务: {len(result['cginstance_tasks'])}个")
    print(f"📋 最近一周任务总计: {result['total_count']}个")
    
    # 显示详细任务信息（已按 cgboss -> cgbundle -> cginstance 顺序排序）
    display_task_details(result, "谭华宝")
    
    # 性能统计
    total_elapsed = time.time() - start_time
    print("\n" + "=" * 80)
    print("⚡ 性能统计:")
    print(f"   数量统计: {count_elapsed:.2f}s")
    print(f"   任务筛选: {filter_elapsed:.2f}s") 
    print(f"   总计耗时: {total_elapsed:.2f}s")
    print(f"   多线程优化: 大大提升了查询效率！")
    print("=" * 80)